import { IView, IObserver, INotification, IMediator } from "../Interfaces";
import { Observer } from "../patterns/observer/Observer";

export class View implements IView {

  mediatorMap: Object = null;
  observerMap: Object = null;
  multitonKey: string = null;
  static MULITON_MSG: string = "View instance for this multiton uid already constructed";
  static instanceMap: Object = {};
  static getInstance(key: string): IView {

    if (!View.instanceMap[key])
      View.instanceMap[key] = new View(key);
    return View.instanceMap[key];
  }

  static removeView(key: string): void {

    delete View.instanceMap[key];
  }

  constructor(key: string) {
    if (View.instanceMap[key])
      throw Error(View.MULITON_MSG);
    View.instanceMap[key] = this;
    this.multitonKey = key;
    this.mediatorMap = {};
    this.observerMap = {};
    this.initializeView();
  }

  initializeView(): void {

  }

  registerObserver(notificationName: string, _observer: IObserver): void {
    let observers: IObserver[] = this.observerMap[notificationName];
    if (observers)
      observers.push(_observer);
    else
      this.observerMap[notificationName] = [_observer];
  }

  removeObserver(notificationName: string, notifyContext: any): void {
    let observers: IObserver[] = this.observerMap[notificationName];
    let i: number = observers.length;
    while (i--) {

      let observer: IObserver = observers[i];
      if (observer.compareNotifyContext(notifyContext)) {
        observers.splice(i, 1);
      }
    }

    if (observers.length == 0)
      delete this.observerMap[notificationName];
  }

  notifyObservers(notification: INotification): void {
    let notificationName: string = notification.getName();

    let observersRef = this.observerMap[notificationName];
    if (observersRef) {

      let observers = observersRef.slice(0);
      let len: number = observers.length;
      for (let i: number = 0; i < len; i++) {

        let observer = observers[i];
       
        observer.notifyObserver(notification);
      }
    }
  }

  registerMediator(mediator: IMediator): void {

    let name: string = mediator.getMediatorName();
    if (this.mediatorMap[name]) return;

    mediator.initializeNotifier(this.multitonKey);

    this.mediatorMap[name] = mediator;

    let interests: string[] = mediator.listNotificationInterests();

    let len: number = interests.length;

    if (len > 0) {

      let observer: IObserver = new Observer(mediator.handleNotification, mediator);

      for (let i: number = 0; i < len; i++)
        this.registerObserver(interests[i], observer);
    }

    mediator.onRegister();
  }


  retrieveMediator(mediatorName: string): IMediator {
    return this.mediatorMap[mediatorName];
  }

  removeMediator(mediatorName: string): IMediator {
    let mediator: IMediator = this.mediatorMap[mediatorName];

    if (!mediator) return null;

    let interests: string[] = mediator.listNotificationInterests();

    let i: number = interests.length;

    while (i--)
      this.removeObserver(interests[i], mediator);
    delete this.mediatorMap[mediatorName];

    mediator.onRemove();
    return mediator;
  }

  hasMediator(mediatorName: string): boolean {
    return this.mediatorMap[mediatorName] != null;
  }
}